#!/bin/bash
#: Title    : fmount (forensic_mount)
#: Author   : "John Lehr" <slo.sleuth@gmail.com>
#: Date     : 07/30/2011
#: Version  : 1.0.0
#: Descript : detect/mount allocated partitions read-only
#: Options  : -u umount -t tskfuse
#: Depends  : sleuthkit, xmount, pytsk
#: License  : GPLv3

## Variables
COUNT=1
DEPS="mmls xmount"
MOUNTER=0
PROGNAME="${0##*/}"
UMOUNT=0

## Functions
check_deps()
{
    for PROG in $DEPS; do
        which $PROG >/dev/null
        if [ $? -gt 0 ]; then
            [[ "$PROG" = "mmls" ]] && PROG=sleuthkit
            echo "Error: $PROG is not installed or is not in the path"
        fi
    done
}

get_image_type()
{
    IMG_TYPE=$(img_stat ${IMAGE[@]} | grep "Image Type:")
    IMG_TYPE=${IMG_TYPE#*:}
    case $IMG_TYPE in
        *raw) ITYPE=dd ;;
        *ewf) ITYPE=ewf ;;
        *aff) ITYPE=aff ;;
    esac
    
    [ -z $IMG_TYPE ] && echo "Error: unknown image type" && exit 1
    
    export ITYPE
}

mount_split_image()
{
    if [ ${#IMAGE[@]} -gt 1 ] || [ "$ITYPE" = "ewf" ]
    then
        MNTPNT="/mnt/$DIR_NAME"
        echo "$ITYPE split image detected consisting of ${#IMAGE[@]} segments" >&2
        mkdir -p $MNTPNT
        xmount --in $ITYPE --out dd "${IMAGE[@]}" "$MNTPNT"
        IMAGE="$MNTPNT/$(basename ${IMAGE%.*}).dd"
        echo "Virtual disk created at $IMAGE" >&2
    else
        IMAGE=$(readlink -f ${IMAGE})
    fi
    export IMAGE
}

mount_volumes()
{
    NTFS_OPTS=
    FSTYPE=
    which tskfuse.py >/dev/null
    if [ $? -eq 0 ] && [ $MOUNTER -eq 1 ] 
    then
        tskfuse.py -o ro,allow_other,offset=$(($OFFSET*512)) "$IMAGE" "$MNTPNT"
        [ $? -gt 0 ] && echo "Mounting error." && exit 1
        TOOL=\"tskfuse.py\"
    else
        [[ "$(fsstat -o $OFFSET $IMAGE | head -3)" =~ NTFS ]] && \
            NTFS_OPTS=,show_sys_files,streams_interface=windows,allow_other && \
            FSTYPE=-t\ ntfs-3g
        mount $FSTYPE -o ro,loop,offset=$(($OFFSET*512)),user$NTFS_OPTS "$IMAGE" "$MNTPNT"
        [ $? -gt 0 ] && echo "Mounting error." && exit 1
        TOOL="\"mount\" command"
    fi
}

usage()
{
    echo "USAGE: $PROGNAME [-ut] IMAGE"

    cat << EOF

$PROGNAME forensic mounter.  Mounts all detected allocated volumes in IMAGE
read-only in the /media directory.  Partitions are named IMAGE_VOLUME.  If
image is split, all segments must be specified.  Split images are first
mounted as a virtual disk in /mnt before partitions are mounted.

Options:
    -h  this help
    -t  use tskfuse to mount partitions (exposes deleted and meta structures)
    -u  umount image partitions

EOF
}

## Check for installed dependencies
check_deps

## list of options program will accept;
## options followed by a colon take arguments
optstring=htu

## The loop calls getops until there are no more options on the command 
## line.  Each option is stored in $opt, any option arguments are stored
## in OPTARG
while getopts $optstring opt; do
    case $opt in
        h) usage >&2; exit 0 ;;
        t) MOUNTER=1 ;;
        u) UMOUNT=1 ;;
        *) echo; usage >&2; exit 1 ;;
    esac
done

## Remove options from the command line
## $OPTIND points to the next, unparsed argument
shift "$(( $OPTIND -1 ))"
IMAGE=($@)
DIR_NAME=$(basename ${IMAGE%.*})

#check for root access
[[ $UID -ne 0 ]] && echo "Root access required." >&2 && exit 1

## Determine volumes and starting offsets
if [ $UMOUNT -eq 1 ]
then
    for DIR in media mnt
    do
        if [ -d /$DIR/$DIR_NAME ]
        then
            echo "Unmounting volumes at /${DIR}/$DIR_NAME/" >&2
            umount /$DIR/$DIR_NAME/* 2>/dev/null
            umount /$DIR/$DIR_NAME 2>/dev/null
            rm -vrf /$DIR/$DIR_NAME
        fi
    done
else
    get_image_type
    mount_split_image
    MMLS=$(mmls -a $IMAGE)
    if [ $? = 0 ]
    then
        echo "$MMLS" | \
        while read LINE
        do
            if [ $COUNT -gt 5 ] #Skip first five lines of MMLS output
            then
                LINE=( $(echo $LINE) ) #make LINE into an array
        
                VOLUME=${LINE[0]/:/} #read first item of array,strip colon
                VOLUME=${VOLUME#0} #strip leading zero
        
                OFFSET=${LINE[2]} #read third item of array
                until [ ${OFFSET:0:1} != 0 ] #strip leading zeros
                do
                    OFFSET=${OFFSET#0}
                done

                MNTPNT="/media/$DIR_NAME/${DIR_NAME}_vol$VOLUME/"
                mkdir -p "$MNTPNT"
                echo "${LINE[5]} file system detected in volume $VOLUME at sector offset $OFFSET" >&2

                mount_volumes
                echo -e "\tmounted at $MNTPNT with $TOOL" >&2
            fi
            COUNT=$(($COUNT+1))
        done
    else
        OFFSET=0
        VOLUME=0
        MNTPNT="/media/$DIR_NAME/${DIR_NAME}_vol$VOLUME/"
        mkdir -p "$MNTPNT"
        echo "Unpartitioned media detected."
        mount_volumes
        echo -e "\tmounted at $MNTPNT with $TOOL" >&2
    fi
fi

exit 0
